package com.yenlien.traceyun.usercenter.service;


import com.yenlien.traceyun.usercenter.bean.DepartmentTree;
import com.yenlien.traceyun.usercenter.dao.DepartmentDao;
import com.yenlien.traceyun.usercenter.dao.DepartmentResourceDao;
import com.yenlien.traceyun.usercenter.dao.UserDao;
import com.yenlien.traceyun.usercenter.entity.Department;
import com.yenlien.traceyun.usercenter.entity.DepartmentResource;
import com.yenlien.traceyun.usercenter.entity.Resource;
import com.yenlien.traceyun.usercenter.entity.User;
import com.yenlien.traceyun.webase.exception.BusinessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by LiuSha on 2020/6/12.
 */
@Service
public class DepartmentService {
    @Autowired
    private DepartmentDao departmentDao;
    @Autowired
    private DepartmentResourceDao departmentResourceDao;
    @Autowired
    private ResourceService menuService;
    @Autowired
    private UserDao userDao;

    public Page<Department> findByList(final Department department) {
        Pageable pageable = PageRequest.of(department.getPage(), department.getPageSize(), Sort.Direction.DESC, "createTime");
        return departmentDao.findAll(new Specification<Department>() {
            private static final long serialVersionUID = 1L;

            @Override
            public Predicate toPredicate(Root<Department> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                Path<String> companyId = root.get("companyId");
                //构造查询条件
                List<Predicate> list = new ArrayList<>();
                if (!StringUtils.isEmpty(department.getCompanyId())) {
                    list.add(cb.equal(companyId, department.getCompanyId()));
                }
                Predicate[] predicate = new Predicate[list.size()];
                return cb.and(list.toArray(predicate));
            }
        }, pageable);
    }

    public void save(Department department) {
        isDepartment(department);
        departmentDao.save(department);
    }

    public void update(Department department) {
        isDepartment(department);
        departmentDao.save(department);
    }

    public void isDepartment(Department department) {
        Department old;
        if (StringUtils.isEmpty(department.getParentId())) {
            old = departmentDao.findByNameAndCompanyId(department.getName(), department.getCompanyId());
        } else {
            old = departmentDao.findByNameAndParentId(department.getName(), department.getParentId());
        }
        if (old != null) {
            throw new BusinessException("500", "部门已经存在！");
        }
    }

    public Department findById(String id) {
        return departmentDao.findById(id);
    }

    public List<Department> findByAll(String companyId) {
        List<Department> departments = departmentDao.findByCompanyId(companyId);
        List<Department> roots = new ArrayList<>();
        List<Department> children = new ArrayList<>();
        if (departments != null && departments.size() > 0) {
            for (Department department : departments) {
                if (StringUtils.isEmpty(department.getParentId())) {
                    roots.add(department);
                } else {
                    children.add(department);
                }
            }
        }
        this.recursion(roots, children);
        return roots;
    }

    /**
     * 根据企业得到链条
     *
     * @param companyId
     * @return
     */
    public List<Department> getChain(String companyId) {
        List<Department> departments = departmentDao.findByCompanyId(companyId);
        List<Department> result = new ArrayList<>();
        parseChain(getRoot(departments), result, departments);
        return result;
    }

    /**
     * 解析子节点
     *
     * @param root
     * @param all
     */
    private void parseTree(List<DepartmentTree> root, List<Department> all) {
        if (all != null && all.size() > 0) {
            Iterator<Department> iterator = all.iterator();
            for (DepartmentTree tree : root) {
                while (iterator.hasNext()) {
                    Department department = iterator.next();
                    if (tree.getId().equals(department.getParentId())) {
                        tree.getChildren().add(DepartmentTree.create(department));
                        iterator.remove();
                    }
                }
                parseTree(tree.getChildren(), all);
            }
        }
    }

    /**
     * 解析根节点
     *
     * @param root
     * @param all
     */
    private void parseRoot(List<DepartmentTree> root, List<Department> all) {
        if (all != null && all.size() > 0) {
            Iterator<Department> iterator = all.iterator();
            while (iterator.hasNext()) {
                Department department = iterator.next();
                if (StringUtils.isEmpty(department.getParentId())) {
                    root.add(DepartmentTree.create(department));
                    iterator.remove();
                }
            }
        }
    }


    /**
     * 获取链条
     *
     * @param start       开始节点
     * @param chooseNodes
     * @param all
     */
    public void parseChain(List<Department> start, List<Department> chooseNodes, List<Department> all) {
        if (start != null && start.size() > 0) {
            for (Department department : start) {
                chooseNodes.add(department);
                List<Department> children = getChild(department, all);
                parseChain(children, chooseNodes, all);
            }
        }
    }

    private List<Department> getChild(Department parent, List<Department> all) {
        List<Department> child = new ArrayList<>();
        if (all != null && all.size() > 0) {
            Iterator<Department> iterator = all.iterator();
            while (iterator.hasNext()) {
                Department department = iterator.next();
                if (parent.getId().equals(department.getParentId())) {
                    child.add(department);
                    iterator.remove();
                }
            }
        }
        return child;
    }

    private List<Department> getRoot(List<Department> all) {
        List<Department> root = new ArrayList<>();
        if (all != null && all.size() > 0) {
            Iterator<Department> iterator = all.iterator();
            while (iterator.hasNext()) {
                Department department = iterator.next();
                if (StringUtils.isEmpty(department.getParentId())) {
                    root.add(department);
                    iterator.remove();
                }
            }
        }
        return root;
    }

    /**
     * 递归操作
     *
     * @param root
     * @param departments
     */
    private void recursion(List<Department> root, List<Department> departments) {
        if (root != null && root.size() > 0) {
            for (Department tree : root) {
                tree.setDepartmentResources(departmentResourceDao.findByDepartmentId(tree.getId()));
                for (Department department : departments) {
                    department.setDepartmentResources(departmentResourceDao.findByDepartmentId(department.getId()));
                    if (tree.getId().equals(department.getParentId())) {
                        List<Department> children = tree.getChildren();
                        if (children == null) {
                            children = new ArrayList<>();
                            tree.setChildren(children);
                        }
                        children.add(department);
                    }
                }
                recursion(tree.getChildren(), departments);
            }
        }
    }

    /**
     * 根据部门id删除
     *
     * @param departmentId
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void dele(String departmentId) {
        List<Department> root = new ArrayList<>();
        Department department = departmentDao.findById(departmentId);
        root.add(department);
        List<Department> choose = new ArrayList<>();
        parseChain(root, choose, departmentDao.findByCompanyId(department.getCompanyId()));
        List<String> departmentIds = choose.stream().map(p -> p.getId()).collect(Collectors.toList());
        departmentDao.deleteAll(choose);
        // userDao.resetUserDepartmentIds(departmentIds);
    }

    /**
     * 绑定资源
     *
     * @param departmentId
     * @param resources
     */
    @Transactional(rollbackFor = RuntimeException.class)
    public void bindResource(String departmentId, List<Resource> resources) {
        departmentResourceDao.deleteByDepartmentId(departmentId);
        if (resources != null && resources.size() > 0) {
            List<DepartmentResource> departmentResources = new ArrayList<>();
            for (Resource resource : resources) {
                DepartmentResource departmentResource = new DepartmentResource();
                departmentResource.setAppId(resource.getAppId());
                departmentResource.setDepartmentId(departmentId);
                departmentResource.setResourceId(resource.getId());
                departmentResources.add(departmentResource);
            }
            departmentResourceDao.saveAll(departmentResources);
        }
    }

    /***************************************/


    @Transactional
    public void delete(String id) {
        List<String> ids = new ArrayList<>();
        delete(id, ids);
        if (ids.size() > 0) {
            for (String i : ids) {
                //删除关联全部
                departmentDao.deleteById(i);
                //删除关联全部的权限
                menuService.deleteDeptMenu(departmentResourceDao.findByDepartmentId(i));
                //删除关联部门的人员部门ID  不删人
                deleteUserDepartmentId(i);
            }
        }
    }

    @Transactional
    public void deleteUserDepartmentId(String departmentId) {
        List<User> users = userDao.findByDepartmentIdAndUserType(departmentId, User.UserType.COMMON);
        if (users.size() > 0) {
            for (User user : users) {
                user.setDepartmentId("");
                userDao.save(user);
            }
        }
    }

    public void delete(String id, List<String> ids) {
        ids.add(id);
        List<Department> departments = departmentDao.findByParentId(id);
        if (departments != null && departments.size() > 0) {
            for (Department department : departments) {
                delete(department.getId(), ids);
            }
        }
    }
}
